在 JavaScript 中,var、let 和 const 都是用来声明变量的关键字。自 ES6 引入 let 和 const 后,它们解决了 var 存在的许多历史遗留问题。
这三者的核心区别主要体现在以下五个维度:
1. 作用域 (Scope)
var:具有函数作用域。只要是在函数内声明的变量,在整个函数内部都有效;如果在函数外声明,则成为全局变量。它不识别代码块(如if、for语句中的{})。let/const:具有块级作用域。变量仅在声明它的代码块({})内部有效,出了代码块就无法访问。
2. 变量提升与暂时性死区 (Hoisting & TDZ)
var:存在变量提升。无论在哪里声明,都会被提升到当前作用域的顶部,并初始化为undefined。因此在声明前访问不会报错,但值为undefined。let/const:虽然也会发生提升,但在执行到声明语句之前,变量处于“暂时性死区”(Temporal Dead Zone, TDZ)。在此期间访问变量会直接抛出ReferenceError错误。
3. 重新赋值与重复声明
var:允许在同一作用域内重复声明同名变量,也允许随时重新赋值。let:不允许在同一作用域内重复声明,但允许重新赋值。const:不允许重复声明,且声明时必须立即初始化,之后不能重新赋值。需要注意的是,const保证的是“绑定的不可变性”。如果const声明的是一个对象或数组,其内存地址不能变,但对象的属性或数组的元素依然可以被修改。
4. 全局对象挂载
var:在全局作用域下使用var声明的变量,会被自动添加为全局对象(如浏览器环境下的window)的属性。let/const:在全局作用域下声明时,不会挂载到全局对象上,从而避免了全局污染。
5. 在 for 循环中的表现
var:循环体内的回调函数共享同一个循环变量。例如经典的异步陷阱,所有定时器打印出的都是循环结束后的最终值。不区分for、if中的{}let:每次循环迭代都会创建一个独立的块级作用域,因此回调函数捕获的是当前轮次的变量值。
最佳实践建议
在现代前端开发中,业界普遍推荐的变量声明优先级为:const > let > var。
- 默认使用
const:当你知道一个变量不需要被重新赋值时,优先使用它,这能清晰地表达意图并防止意外修改。 - 需要修改时用
let:仅当明确知道变量后续需要被更新(如计数器、状态切换)时才使用let。 - 避免使用
var:除非是为了维护老旧代码或兼容特殊场景,否则应全面弃用var。